using System;
using System.Collections.Generic;
using System.Text;

namespace Toenda.Foundation.Types {
	/// <summary>
    /// Struct IP
    /// </summary>
	public struct IP {
		private IPVersion _version;
		private string _ip_complete;
		private string _ip_part_1;
		private string _ip_part_2;
		private string _ip_part_3;
		private string _ip_part_4;
		private string _ip_part_5;
		private string _ip_part_6;

		// ---------------------------------------------------
		// CONSTRUCTORS
		// ---------------------------------------------------

		/// <summary>
		/// Default Ctor
		/// </summary>
		/// <param name="value"></param>
		public IP(string value) {
			this._ip_part_1 = "";
			this._ip_part_2 = "";
			this._ip_part_3 = "";
			this._ip_part_4 = "";
			this._ip_part_5 = "";
			this._ip_part_6 = "";
			this._version = IPVersion.IP4;

			this._ip_complete = value;

			this._ParseStringToFragments(this._version);
			this._RepairFalseIPFragment();
		}

		/// <summary>
		/// Specific Ctor
		/// </summary>
		/// <param name="version"></param>
		/// <param name="value"></param>
		public IP(IPVersion version, string value) {
			this._ip_part_1 = "";
			this._ip_part_2 = "";
			this._ip_part_3 = "";
			this._ip_part_4 = "";
			this._ip_part_5 = "";
			this._ip_part_6 = "";
			this._version = IPVersion.IP4;

			this._version = version;
			this._ip_complete = value;

			this._ParseStringToFragments(version);
			this._RepairFalseIPFragment();
		}

		/// <summary>
		/// Specific Ctor
		/// </summary>
		/// <param name="part1"></param>
		/// <param name="part2"></param>
		/// <param name="part3"></param>
		/// <param name="part4"></param>
		public IP(string part1, string part2, string part3, string part4) {
			this._version = IPVersion.IP4;
			this._ip_part_1 = part1;
			this._ip_part_2 = part2;
			this._ip_part_3 = part3;
			this._ip_part_4 = part4;
			this._ip_part_5 = "";
			this._ip_part_6 = "";
			this._ip_complete = part1 + part2 + part3 + part4;
			this._RepairFalseIPFragment();
		}

		// ---------------------------------------------------
		// INTERFACE IMPLEMENTATIONS
		// ---------------------------------------------------

		// ---------------------------------------------------
		// PROPERTIES
		// ---------------------------------------------------

		/// <summary>
		/// Get or set the correct IP string
		/// </summary>
		public string Address {
			get { return this._ConvertToIP(); }
			set {
				this._ip_complete = value;
				this._ParseStringToFragments(IPVersion.IP4);
				this._RepairFalseIPFragment();
			}
		}

		// ---------------------------------------------------
		// EVENTS
		// ---------------------------------------------------

		// ---------------------------------------------------
		// PRIVATE MEMBERS
		// ---------------------------------------------------

		/// <summary>
		/// Parse a complete string into all fragment types
		/// </summary>
		/// <param name="version"></param>
		private void _ParseStringToFragments(IPVersion version) {
			string[] array = this._ip_complete.Split(new char[] { '.' });
			this._ip_part_1 = array[0];
			this._ip_part_2 = array[1];
			this._ip_part_3 = array[2];
			this._ip_part_4 = array[3];

			if(version == IPVersion.IP6) {
				this._ip_part_5 = array[4];
				this._ip_part_6 = array[5];
			}
			else {
				this._ip_part_5 = "";
				this._ip_part_6 = "";
			}
		}

		/// <summary>
		/// Checks the ip string fragment
		/// </summary>
		/// <param name="fragment"></param>
		/// <returns></returns>
		private bool _CheckIPStringFragment(string fragment) {
			if(fragment.Trim() != "") {
				int chk = 0;

				int.TryParse(fragment, out chk);

				if(chk > 255) {
					return false;
				}
			}

			return true;
		}

		/// <summary>
		/// Repair the false ip fragments
		/// </summary>
		private void _RepairFalseIPFragment() {
			if(!this._CheckIPStringFragment(this._ip_part_1)) {
				this._ip_part_1 = "255";
			}

			if(!this._CheckIPStringFragment(this._ip_part_2)) {
				this._ip_part_2 = "255";
			}

			if(!this._CheckIPStringFragment(this._ip_part_3)) {
				this._ip_part_3 = "255";
			}

			if(!this._CheckIPStringFragment(this._ip_part_4)) {
				this._ip_part_4 = "255";
			}

			if(this._ip_part_5.Trim() != "") {
				if(!this._CheckIPStringFragment(this._ip_part_5)) {
					this._ip_part_5 = "255";
				}
			}

			if(this._ip_part_6.Trim() != "") {
				if(!this._CheckIPStringFragment(this._ip_part_6)) {
					this._ip_part_6 = "255";
				}
			}
		}

		/// <summary>
		/// Convert the data into a correct ip string
		/// </summary>
		/// <returns></returns>
		private string _ConvertToIP() {
			StringBuilder str = new StringBuilder();

			str.Append(this._ip_part_1);
			str.Append(".");
			str.Append(this._ip_part_2);
			str.Append(".");
			str.Append(this._ip_part_3);
			str.Append(".");
			str.Append(this._ip_part_4);

			if(this._version == IPVersion.IP6) {
				str.Append(".");
				str.Append(this._ip_part_5);
				str.Append(".");
				str.Append(this._ip_part_6);
			}

			return str.ToString();
		}

		// ---------------------------------------------------
		// PROTECTED MEMBERS
		// ---------------------------------------------------

		// ---------------------------------------------------
		// PUBLIC MEMBERS
		// ---------------------------------------------------

		/// <summary>
		/// Initialize a IP object with a string
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static implicit operator IP(string value) {
			return new IP(value);
		}

		/// <summary>
		/// Returns the fragment string as a ip adress
		/// </summary>
		/// <returns></returns>
		public override string ToString() {
			return this._ConvertToIP();
		}

		/// <summary>
		/// Parse a string into a IP
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static IP Parse(string value) {
			return new IP(value);
		}

		/// <summary>
		/// Parse a string into a IP
		/// </summary>
		/// <param name="version"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public static IP Parse(IPVersion version, string value) {
			return new IP(version, value);
		}

		/// <summary>
		/// Parse a string into a IP
		/// </summary>
		/// <param name="part1"></param>
		/// <param name="part2"></param>
		/// <param name="part3"></param>
		/// <param name="part4"></param>
		/// <returns></returns>
		public static IP Parse(string part1, string part2, string part3, string part4) {
			return new IP(part1, part2, part3, part4);
		}
	}
}